package xyz.wadewhy.basicstest.juc;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;

/**
 * @ClassName VariableSafety
 * @Description 变量是否安全
 * @Author zhongzihao
 * @Date 2021/12/28 4:20 下午
 * @Version 1.0
 **/
@Slf4j(topic = "c.VariableSafety")
class VariableSafety {
    static final int THREAD_NUMBER = 2;
    static final int LOOP_NUMBER = 200;

    public static void main(String[] args) {
//        localVariableDemo();
//        localVariableDemoV2();
        localVariableDemoV3();
    }

    /**
     * 局部变量基本类型是线程安全的
     */
    public static void localVariableDemo() {
        new Thread(VariableSafety::test1, "localVariableDemo1").start();
        new Thread(VariableSafety::test1, "localVariableDemo2").start();
    }

    /**
     * 成员变量，线程不安全
     */
    public static void localVariableDemoV2() {
        ThreadUnsafe test = new ThreadUnsafe();
        for (int i = 0; i < THREAD_NUMBER; i++) {
            new Thread(() -> {
                try {
                    test.method1(LOOP_NUMBER);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "localVariableDemoV2" + i).start();
        }
    }

    /**
     * 局部变量，线程安全
     */
    public static void localVariableDemoV3() {
        ThreadSafe test = new ThreadSafe();
        for (int i = 0; i < THREAD_NUMBER; i++) {
            new Thread(() -> {
                try {
                    test.method1(LOOP_NUMBER);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "localVariableDemoV2" + i).start();
        }
    }
    public static void test1() {
        int i = 1;
        i++;
        log.debug("localVariableDemo -- i= {}", i);
    }
}

/**
 * 成员变量的引用不安全
 */
class ThreadUnsafe {
    ArrayList<String> list = new ArrayList<>();

    public void method1(int loopNumber) throws InterruptedException {
        for (int i = 0; i < loopNumber; i++) {
            // { 临界区, 会产生竞态条件
            //这里method2睡眠200ms，以便模拟其他线程提前执行method3，线程不安全
            method2();
            method3();
            // } 临界区
        }
    }

    private void method2() throws InterruptedException {
        Thread.sleep(200);
        list.add("1");
    }

    private void method3() {
        list.remove(0);
    }
}
@Slf4j(topic = "c.ThreadSafe")
class ThreadSafe {
    public final void method1(int loopNumber) throws InterruptedException {
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < loopNumber; i++) {
            method2(list);
            method3(list);
        }
    }

    private void method2(ArrayList<String> list ) throws InterruptedException {
        Thread.sleep(200);
        list.add("1");
        log.info("add list: {}", list);
    }

    private void method3(ArrayList<String> list ) {
        list.remove(0);
        log.info("add list: {}", list);
    }
}